home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Drivers / play3401 / play3401.c < prev    next >
C/C++ Source or Header  |  1994-03-02  |  11KB  |  467 lines

  1. /* -*-C-*-
  2. *******************************************************************************
  3. *
  4. * File:         play3401.c
  5. * RCS:          /usr/local/lib/cvs/play3401/play3401.c,v 1.3 1994/03/03 19:10:36 cedman Exp
  6. * Description:  Play Toshiba 3401
  7. * Author:       Carl Edman
  8. * Created:      Wed May  5 21:34:47 1993
  9. * Modified:     Thu Mar  3 13:48:25 1994 (Carl Edman) cedman@capitalist.princeton.edu
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       Alpha
  13. *
  14. * (C) Copyright 1993, but otherwise this file is perfect freeware.
  15. *
  16. *******************************************************************************
  17. */
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <libc.h>
  24. #include <signal.h>
  25. #include <errno.h>
  26. #include <sys/file.h>
  27. #include <sys/types.h>
  28. #include <sys/resource.h>
  29. #include <sound/sound.h>
  30. #include <sound/sounddriver.h>
  31. #include <sound/utilsound.h>
  32. #include "scsicommands.h"
  33.  
  34. #define BCD(c) (((c)%10)+((((c)/10)%10)<<4))
  35. #define BLOCKSIZE (2352)
  36. #define BUFBLOCK (6*75)
  37. #define READBLOCK (27)
  38. #define TRACKNO (100)
  39.  
  40. #define GETNO() for(c=0;isascii(*d) && isdigit(*d);d++) c= (c*10)+(*d-'0')
  41.  
  42. struct Mode
  43.    {
  44.    u_int data_length:8,
  45.          medium_type:8,
  46.          dev_parameter:8,
  47.          bdescriptor_length:8;
  48.    u_int density:8,
  49.          nblocks:24;
  50.    u_int mbz1:8,
  51.          block_length:24;
  52.    };
  53.  
  54. struct Toc_track_descriptor
  55.    {
  56.    u_int mbz1:8,
  57.          adr:4,
  58.          control:4,
  59.          track_number:8,
  60.          mbz2:8;
  61.    u_int address;
  62.    };
  63.  
  64. struct Toc
  65.    {
  66.    u_int toc_data_length:16,
  67.          first:8,
  68.          last:8;
  69.    struct Toc_track_descriptor track[TRACKNO];
  70.    };
  71.  
  72. volatile int done,fillup;
  73. volatile int readp,playp;
  74. port_t devicePort,ownerPort,streamPort,replyPort;
  75. condition_t sync_threads;
  76. mutex_t position;
  77. cthread_t play_t;
  78. char *buf;
  79. struct Toc toc;
  80. int errflg=0,dontejectflg=0,recordflg=0,playflg=0;
  81.  
  82. extern int getopt(int ac,char *av[],char *opts);
  83. extern int optind;
  84. extern char *optarg;
  85.  
  86. int interpret_duration(const char *str,int *sf,int *ef)
  87.    {
  88.    int c,i;
  89.    const char *d;
  90.  
  91.    for(i=0,d=str;*d;d++) if (*d=='-') i++;
  92.    if (i>1) return -1;
  93.  
  94.    d=str;
  95.  
  96.    if (*d=='#')
  97.       {
  98.       d++;
  99.       GETNO();
  100.       for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==c) break;
  101.       if (i>=TRACKNO) return -1;
  102.       *sf=toc.track[i].address;
  103.       if (*d=='+') d++;
  104.       }
  105.    else
  106.       {
  107.       *sf=toc.track[0].address;
  108.       }
  109.  
  110.    if (*d && *d!='-')
  111.       {
  112.       GETNO();
  113.       if (*d==':')
  114.          {
  115.          d++;
  116.          *sf+=c*60*75;
  117.          GETNO(); if (c>=60) return -1;
  118.          *sf+=c*75;
  119.          if (*d==':')
  120.             {
  121.             d++;
  122.             GETNO(); if (c>=75) return -1;
  123.             *sf+=c;
  124.             }
  125.          }
  126.       else
  127.          {
  128.          *sf+=c;
  129.          }
  130.       }
  131.  
  132.    if (!*d) d=str; else if (*d=='-') d++; else return -1;
  133.    
  134.    if (*d=='#')
  135.       {
  136.       d++;
  137.       GETNO();
  138.       for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==c) break;
  139.       if (i>=TRACKNO) return -1;
  140.       if (*d=='+')
  141.          {
  142.          *ef=toc.track[i].address;
  143.          d++;
  144.          }
  145.       else
  146.          {
  147.          *ef=toc.track[i+1].address;
  148.          }
  149.       }
  150.    else if (*d=='\0')
  151.       {
  152.       for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==0xaa) break;
  153.       if (i>=TRACKNO) return -1;
  154.       *ef=toc.track[i].address;
  155.       }
  156.    else
  157.       {
  158.       *ef=toc.track[0].address;
  159.       }
  160.  
  161.    if (*d && *d!='-')
  162.       {
  163.       GETNO();
  164.       if (*d==':')
  165.          {
  166.          d++;
  167.          *ef+=c*60*75;
  168.          GETNO(); if (c>=60) return -1;
  169.          *ef+=c*75;
  170.          if (*d==':')
  171.             {
  172.             d++;
  173.             GETNO(); if (c>=75) return -1;
  174.             *ef+=c+1;
  175.             }
  176.          else
  177.             {
  178.             *ef+=75;
  179.             }
  180.          }
  181.       else
  182.          {
  183.          *ef+=c+1;
  184.          }
  185.       }
  186.  
  187.    if (*d && *d!=-1) return -1;
  188.    if (*sf<toc.track[0].address) return -1;
  189.    for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==0xaa) break;
  190.    if (i>=TRACKNO) return -1;
  191.    if (*ef>toc.track[i].address) return -1;
  192.    return (*sf<*ef);
  193.    } 
  194.  
  195. void play_suspend(int sig)
  196.    {
  197.    snddriver_stream_control(streamPort,0,SNDDRIVER_PAUSE_STREAM);
  198.    signal(sig,SIG_DFL);
  199.    raise(sig);
  200.    }
  201.  
  202. void play_continue(int sig)
  203.    {
  204.    signal(SIGTSTP,play_suspend);
  205.    snddriver_stream_control(streamPort,0,SNDDRIVER_RESUME_STREAM);
  206.    }
  207.  
  208. void setdone(int sig)
  209.    {
  210.    snddriver_stream_control(streamPort,0,SNDDRIVER_ABORT_STREAM);
  211.    done=1;
  212.    }
  213.  
  214. void play_completed(void *arg,int tag)
  215.    {
  216.    playp=tag;
  217.    }
  218.  
  219. any_t play_thread(any_t arg)
  220.    {
  221.    int rp,pp,tp,ep;
  222.    unsigned short *p,*e,*r;
  223.    int protocol=0;
  224.    int err;
  225.    snddriver_handlers_t handlers = { 0,0,0,play_completed,0,0,0,0,0,0,0,0 };
  226.    msg_header_t *replyMsg = 0;
  227.  
  228.    if (playflg)
  229.       {
  230.       replyMsg=malloc(MSG_SIZE_MAX);
  231.       port_allocate(task_self(),&replyPort);
  232.       SNDAcquire(SND_ACCESS_OUT,10,0,0,0,0,&devicePort,&ownerPort);
  233.       snddriver_stream_setup(devicePort,ownerPort,SNDDRIVER_STREAM_TO_SNDOUT_44,vm_page_size/2,2,176400,352800,&protocol,&streamPort);
  234.       }
  235.    
  236.    mutex_lock(position);
  237.    tp=readp;
  238.    while(!done)
  239.       {
  240.       while (!done && ((fillup && (readp<playp+(BUFBLOCK*3)/4))||
  241.                        (!fillup && (readp<=tp))))
  242.          condition_wait(sync_threads,position);
  243.       fillup=0;
  244.       rp=readp; pp=playp;
  245.       mutex_unlock(position);
  246.       ep=tp;
  247.       while (tp<rp)
  248.          {
  249.          ep=tp+75;
  250.          if (ep>rp) ep=rp;
  251.          if (tp%BUFBLOCK+(ep-tp)>BUFBLOCK) ep=tp+BUFBLOCK-(tp%BUFBLOCK);
  252.          p=(unsigned short *)(buf+((tp%BUFBLOCK)*BLOCKSIZE));
  253.          e=(unsigned short *)(buf+((((ep-1)%BUFBLOCK)+1)*BLOCKSIZE));
  254.          for(r=p;r<e;r++) *r=NXSwapShort(*r);
  255.  
  256.          if (playflg)
  257.             err=snddriver_stream_start_writing(streamPort,
  258.                                                p,e-p,
  259.                                                ep,
  260.                                                0,0,
  261.                                                0,1,0,0,0,0,
  262.                                                replyPort);
  263.          if (recordflg) write(1,p,(e-p)*sizeof(*p));
  264.          tp=ep;
  265.          }
  266.       
  267.       mutex_lock(position);
  268.       if (playflg)
  269.          {
  270.          replyMsg->msg_size=MSG_SIZE_MAX;
  271.          replyMsg->msg_local_port=replyPort;
  272.          while (msg_receive(replyMsg, RCV_TIMEOUT,0)==RCV_SUCCESS)
  273.             {
  274.             err=snddriver_reply_handler(replyMsg,&handlers);
  275.             if (playp>=tp) fillup=1;
  276.             condition_broadcast(sync_threads);
  277.             }
  278.          }
  279.       else
  280.          {
  281.          playp=ep;
  282.          condition_broadcast(sync_threads);
  283.          }
  284.       }
  285.    done=1;
  286.    mutex_unlock(position);
  287.    
  288.    if (playflg)
  289.       {
  290.       free(replyMsg);
  291.       port_deallocate(task_self(),replyPort);
  292.       SNDRelease(SND_ACCESS_OUT,devicePort,ownerPort);
  293.       }
  294.    
  295.    return arg;
  296.    }
  297.  
  298. int main(int ac,char *av[])
  299.    {
  300.    int c;
  301.    int startframe,endframe;
  302.    struct Mode page,opage;
  303.  
  304.    while((c=getopt(ac,av,"epr"))!=EOF) switch(c)
  305.       {
  306.     case 'e':
  307.       dontejectflg++;
  308.       break;
  309.     case 'p':
  310.       playflg++;
  311.       break;
  312.     case 'r':
  313.       recordflg++;
  314.       break;
  315.     case '?':
  316.     default:
  317.       errflg++;
  318.       }
  319.  
  320.    if (geteuid())
  321.       {
  322.       fprintf(stderr,"%s was not installed SUID root.\n",av[0]);
  323.       exit(1);
  324.       }
  325.  
  326.    if (errflg)
  327.       {
  328.       fprintf(stderr,"Usage: %s -e duration ...\n",av[0]);
  329.       exit(2);
  330.       }
  331.    
  332.    if (playflg==0 && recordflg==0)
  333.       playflg++;
  334.  
  335.    position=mutex_alloc();
  336.    
  337.    sync_threads=condition_alloc();
  338.    
  339.    signal(SIGHUP ,setdone); signal(SIGINT ,setdone); signal(SIGQUIT,setdone);
  340.    signal(SIGILL ,setdone); signal(SIGTRAP,setdone); signal(SIGIOT ,setdone);
  341.    signal(SIGEMT ,setdone); signal(SIGFPE ,setdone); signal(SIGBUS ,setdone);
  342.    signal(SIGSEGV,setdone); signal(SIGSYS ,setdone); signal(SIGPIPE,setdone);
  343.    signal(SIGTERM,setdone); signal(SIGXCPU,setdone); signal(SIGXFSZ,setdone);
  344.  
  345.    signal(SIGTSTP,play_suspend); signal(SIGCONT,play_continue);
  346.    
  347.    scsisettimeout(10);
  348.    if ((scsigetdev("TOSHIBA CD-ROM XM-3401TA")==-1) &&
  349.        (scsigetdev("TOSHIBA CD-ROM XM-4101TA")==-1))
  350.       {
  351.       fprintf(stderr,"Can't find Toshiba 3401 (or later) CD player -- %s only works with it.\n",av[0]);
  352.       exit(3);
  353.       }
  354.  
  355.    if (scsiread6s(&opage,sizeof(opage),0x1a,0,0,0,sizeof(opage),0))
  356.       {
  357.       fprintf(stderr,"Can't read mode page.\n");
  358.       exit(4);
  359.       }
  360.    
  361.    opage.data_length=0;
  362.    page=opage;
  363.    page.density=0x82;
  364.    page.block_length=0x930;
  365.    
  366.    if (scsiwrite6s(&page,sizeof(page),0x15,0,0,0,sizeof(page),0))
  367.       {
  368.       fprintf(stderr,"Can't write mode page.\n");
  369.       exit(5);
  370.       }
  371.    
  372.    buf=malloc(BUFBLOCK*BLOCKSIZE);
  373.    done=0;
  374.    fillup=1;
  375.  
  376.    if (scsiread10(&toc,sizeof(toc),0x43,0,0,0,1,0,0,0,sizeof(toc),0))
  377.       {
  378.       fprintf(stderr,"Can't read CDs table of contents.\n");
  379.       goto end;
  380.       }
  381.    
  382.    for(c=0;c<TRACKNO;c++)
  383.       {
  384.       int i=toc.track[c].address;
  385.       toc.track[c].address=(i&0xff)+75*((i>>8)&0xff)+75*60*((i>>16)&0xff);
  386.       }
  387.  
  388.    setpriority(PRIO_PROCESS,0,-10);
  389.    
  390.    playp=readp=0;
  391.    play_t=cthread_fork(play_thread,0);
  392.       
  393.     if (recordflg)
  394.        {
  395.        SNDSoundStruct sndheader;
  396.        sndheader.magic=SND_MAGIC;
  397.        sndheader.dataLocation=28;
  398.        sndheader.dataSize=0;    /* a lie, but /usr/bin/sndplay dosen't care */
  399.        sndheader.dataFormat=SND_FORMAT_LINEAR_16;
  400.        sndheader.samplingRate=SND_RATE_HIGH;
  401.        sndheader.channelCount=2;
  402.        sndheader.info[0]=0;
  403.        sndheader.info[1]=0;
  404.        sndheader.info[2]=0;
  405.        sndheader.info[3]=0;
  406.        write(1,&sndheader,28);  /* write 28-byte header */
  407.        }
  408.  
  409.    for(c=optind;(c<ac) && !done;c++)
  410.       {
  411.       int offset,rp,pp,ep;
  412.       if (!strcmp(av[c],"repeat"))
  413.          {
  414.          if (c==optind)
  415.             {
  416.             fprintf(stderr,"No durations before repeat\n");
  417.             continue;
  418.             }
  419.          c=optind;
  420.          }
  421.       if (interpret_duration(av[c],&startframe,&endframe)==-1)
  422.          {
  423.          fprintf(stderr,"Bad duration specificitation: %s\n",av[c]);
  424.          continue;
  425.          }
  426.  
  427.       mutex_lock(position);
  428.       offset=startframe-readp;
  429.       startframe-=offset;
  430.       endframe-=offset;
  431.       
  432.       while(!done && readp<endframe)
  433.          {
  434.          while ((playp+BUFBLOCK<=readp) && !done) condition_wait(sync_threads,position);
  435.          rp=readp; pp=playp;
  436.          
  437.          ep=rp+READBLOCK;
  438.          if (ep>endframe) ep=endframe;
  439.          if (rp%BUFBLOCK+(ep-rp)>BUFBLOCK) ep=rp+BUFBLOCK-(rp%BUFBLOCK);
  440.          if (pp+BUFBLOCK<ep) ep=pp+BUFBLOCK;
  441.  
  442.          if (ep>rp)
  443.             {
  444.             mutex_unlock(position);
  445.             if (scsiread10(buf+(rp%BUFBLOCK)*BLOCKSIZE,(ep-rp)*BLOCKSIZE,0x28,0,0,0,0,0,(BCD((rp+offset)/(75*60))<<24)+(BCD(((rp+offset)/75)%60)<<16)+(BCD((rp+offset)%75)<<8),0,ep-rp,1<<6)) goto end;
  446.             mutex_lock(position);
  447.             rp=readp=ep;
  448.             condition_broadcast(sync_threads);
  449.             }
  450.          }
  451.       mutex_unlock(position);
  452.       }
  453.  end:
  454.    done=1;
  455.    condition_broadcast(sync_threads);
  456.    cthread_join(play_t);
  457.    if (scsiwrite6s(&opage,sizeof(opage),0x15,0,0,0,sizeof(opage),0))
  458.       {
  459.       fprintf(stderr,"Can't reset mode page.\n");
  460.       }
  461.    if (scsiclose(!dontejectflg))
  462.       {
  463.       fprintf(stderr,"Can't eject CD.\n");
  464.       }
  465.    exit(0);
  466.    }
  467.